package com.yricky.astral.ability

import com.yricky.astral.signal.Reg
import com.yricky.astral.signal.Signal
import com.yricky.astral.signal.Wire
import com.yricky.astral.structure.ClkRstPair
import com.yricky.astral.structure.AstralModule
import com.yricky.astral.structure.scope.ModuleScope
import com.yricky.astral.structure.scope.ModuleScopeBasic

fun AAModule(name:String,logic: AbilityModuleScope.()->Unit):AstralModule{
    return object :AbilityModule(name),AbilityModuleScope{
        override fun logic() {
            logic.invoke(this)
        }
    }
}

fun ImplModule(name:String,logic: ImplModuleScope.()->Unit):AstralModule{
    return object :AbilityModule(name),ImplModuleScope{
        override fun logic() {
            logic.invoke(this)
        }
    }
}

fun AbilityModuleScopeBasic.InputWire(name:String,width:Int = 1,use:((Wire)-> Unit)? = null): Wire {
    return inputWire(name, width).also { use?.invoke(it) }
}

fun AbilityModuleScopeBasic.OutputWire(name:String,width:Int = 1,assign:((Wire)-> Signal)): Wire {
    return outputWire(name, width).also { it assignTo assign.invoke(it) }
}

fun AbilityModuleScopeBasic.Wire(name:String,width:Int = 1,assign:((Wire)-> Signal)): Wire {
    return wire(name, width).also { it assignTo assign.invoke(it) }
}

fun AbilityModuleScope.Reg(name:String,width:Int = 1,assign:((Reg)-> Signal)): Reg {
    return reg(name, width).also { it assignTo assign.invoke(it) }
}

fun AbilityModuleScope.OutputReg(name:String,width:Int = 1,clkRstPair: ClkRstPair? = clkRstPairStack.lastOrNull(),assign:((Reg)-> Signal)): Reg {
    return outputReg(name, width,clkRstPair).also { it assignTo assign.invoke(it) }
}

fun AbilityModuleScope.Timing(clkName:String,rstName:String,logic: AbilityModuleScope.()->Unit): ClkRstPair {
    return Timing(InputWire(clkName),InputWire(rstName),logic)
}

fun AbilityModuleScope.Timing(clk:Wire,rst:Wire,logic: AbilityModuleScope.()->Unit): ClkRstPair {
    return Timing(ClkRstPair(clk,rst),logic)
}

fun AbilityModuleScope.Timing(clkRstPair: ClkRstPair, logic: AbilityModuleScope.()->Unit): ClkRstPair {
    clkRstPairStack.add(clkRstPair)
    logic.invoke(this)
    return clkRstPairStack.removeLast()
}